/******************************************************************************\
    HttpResponse.h discribes classes of various http responses.
    Copyright (C) 2008  Victor Vinogradov (fly3333@gmail.com)

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
\******************************************************************************/

#pragma once

#include <string>
#include <Common\File.hpp>
#include <map>
#include <Common\Memory.hpp>
#include <Common\Object.hpp>

class cWardHttpResponse
{
protected:
	static std::string TimeStr( unsigned long long time );
public:
	virtual int Get() = 0;
	virtual unsigned long long GetLength() const = 0;
	virtual int GetStatusCode() const = 0;
	virtual const char *GetComment() const = 0;
	virtual std::map< std::string, std::string > GetContentInfo() const = 0;
};

class cDataResponse : public cWardHttpResponse
{
private:
	std::string ContentData;
	unsigned long ContentOffset;
	unsigned long long Time;
public:
	cDataResponse( const std::string &data );
	virtual int Get();
	virtual unsigned long long GetLength() const;
	virtual int GetStatusCode() const = 0;
	virtual const char *GetComment() const = 0;
	virtual std::map< std::string, std::string > GetContentInfo() const;
};

class cOkResponse : public cDataResponse
{
	std::string MimeType;
public:
	cOkResponse( const std::string &data, const std::string &mime_type );
	virtual int GetStatusCode() const;
	virtual const char *GetComment() const;
	virtual std::map< std::string, std::string > cOkResponse::GetContentInfo() const;
};

class cNotFoundResponse : public cDataResponse
{
public:
	cNotFoundResponse( const std::string &data );
	virtual int GetStatusCode() const;
	virtual const char *GetComment() const;
};

class cForbiddenResponse : public cDataResponse
{
public:
	cForbiddenResponse( const std::string &data );
	virtual int GetStatusCode() const;
	virtual const char *GetComment() const;
};

class cEmptyResponse : public cWardHttpResponse
{
public:
	virtual int Get();
	virtual unsigned long long GetLength() const;
	virtual int GetStatusCode() const = 0;
	virtual const char *GetComment() const = 0;
	virtual std::map< std::string, std::string > GetContentInfo() const = 0;
};

class cMovedPermanentlyResponse : public cEmptyResponse
{
private:
	std::string Location;
public:
	cMovedPermanentlyResponse( const std::string &location );
	virtual int GetStatusCode() const;
	virtual const char *GetComment() const;
	virtual std::map< std::string, std::string > GetContentInfo() const;
};

class cFoundResponse : public cEmptyResponse
{
private:
	std::string Location;
public:
	cFoundResponse( const std::string &location );
	virtual int GetStatusCode() const;
	virtual const char *GetComment() const;
	virtual std::map< std::string, std::string > GetContentInfo() const;
};

class cSetCookieResponse : public cFoundResponse
{
private:
	std::string Cookie;
public:
	cSetCookieResponse( const std::string &location, const std::string &cookie );
	virtual std::map< std::string, std::string > GetContentInfo() const;
};

class cSeeOtherResponse : public cEmptyResponse
{
private:
	std::string Location;
public:
	cSeeOtherResponse( const std::string &location );
	virtual int GetStatusCode() const;
	virtual const char *GetComment() const;
	virtual std::map< std::string, std::string > GetContentInfo() const;
};

class cBaseFileResponse : public cWardHttpResponse
{
private:
	cMemory< char > Buffer;
	unsigned long BufferOffset, BufferSize, MaxBufferSize;
protected:
	cFile File;
	unsigned long long FirstOffset, CurrentOffset, LastOffset;
public:
	cBaseFileResponse( const cFile &file, unsigned long long offset_first, unsigned long long offset_last, unsigned long max_buffer_size );
	virtual int Get();
	virtual unsigned long long GetLength() const;
	virtual int GetStatusCode() const = 0;
	virtual const char *GetComment() const = 0;
	virtual std::map< std::string, std::string > GetContentInfo() const;
};

class cFileResponse : public cBaseFileResponse
{
public:
	cFileResponse( const cFile &file, unsigned long max_buffer_size );
	virtual int GetStatusCode() const;
	virtual const char *GetComment() const;
};

class cPartialFileResponse : public cBaseFileResponse
{
public:
	cPartialFileResponse( const cFile &file, unsigned long long offset_first, unsigned long long offset_last, unsigned long max_buffer_size );
	virtual int GetStatusCode() const;
	virtual const char *GetComment() const;
	virtual std::map< std::string, std::string > GetContentInfo() const;
};

class cHttpResponse : public cPointerObject< cWardHttpResponse >
{
public:
	bool CreateOkResponse( const std::string &data, const std::string &mime_type = "text/html" )
	{
		cOkResponse *ok_response;
		try
		{
			ok_response = new cOkResponse( data, mime_type );
		}
		catch( ... )
		{
			return false;
		}
		if( !SwitchToWardObject( ok_response ) )
		{
			delete ok_response;
			return false;
		}
		return true;
	}
	bool CreateNotFoundResponse( const std::string &data )
	{
		cNotFoundResponse *not_found_response;
		try
		{
			not_found_response = new cNotFoundResponse( data );
		}
		catch( ... )
		{
			return false;
		}
		if( !SwitchToWardObject( not_found_response ) )
		{
			delete not_found_response;
			return false;
		}
		return true;
	}
	bool CreateForbiddenResponse( const std::string &data )
	{
		cForbiddenResponse *forbidden_response;
		try
		{
			forbidden_response = new cForbiddenResponse( data );
		}
		catch( ... )
		{
			return false;
		}
		if( !SwitchToWardObject( forbidden_response ) )
		{
			delete forbidden_response;
			return false;
		}
		return true;
	}
	bool CreateMovedPermanentlyResponse( const std::string &location )
	{
		cMovedPermanentlyResponse *moved_permanently_response;
		try
		{
			moved_permanently_response = new cMovedPermanentlyResponse( location );
		}
		catch( ... )
		{
			return false;
		}
		if( !SwitchToWardObject( moved_permanently_response ) )
		{
			delete moved_permanently_response;
			return false;
		}
		return true;
	}
	bool CreateSetCookieResponse( const std::string &location, const std::string &cookie )
	{
		cSetCookieResponse *set_cookie_response;
		try
		{
			set_cookie_response = new cSetCookieResponse( location, cookie );
		}
		catch( ... )
		{
			return false;
		}
		if( !SwitchToWardObject( set_cookie_response ) )
		{
			delete set_cookie_response;
			return false;
		}
		return true;
	}
	bool CreateFoundResponse( const std::string &location )
	{
		cFoundResponse *found_response;
		try
		{
			found_response = new cFoundResponse( location );
		}
		catch( ... )
		{
			return false;
		}
		if( !SwitchToWardObject( found_response ) )
		{
			delete found_response;
			return false;
		}
		return true;
	}
	bool CreateFileResponse( const cFile &file, unsigned long max_buffer_size = 65536 )
	{
		cFileResponse *file_response;
		try
		{
			file_response = new cFileResponse( file, max_buffer_size );
		}
		catch( ... )
		{
			return false;
		}
		if( !SwitchToWardObject( file_response ) )
		{
			delete file_response;
			return false;
		}
		return true;
	}
	bool CreatePartialFileResponse( const cFile &file, unsigned long long offset_first, unsigned long long offset_last, unsigned long max_buffer_size = 65536 )
	{
		cPartialFileResponse *partial_file_response;
		try
		{
			partial_file_response = new cPartialFileResponse( file, offset_first, offset_last, max_buffer_size );
		}
		catch( ... )
		{
			return false;
		}
		if( !SwitchToWardObject( partial_file_response ) )
		{
			delete partial_file_response;
			return false;
		}
		return true;
	}
	void Destroy()
	{
		SwitchToSubObject( NULL );
	}
};
